home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / PowerMacOberon 1.2 / Source / Tools / Find.Mod (.txt) < prev    next >
Oberon Text  |  1995-08-22  |  17KB  |  452 lines

  1. Syntax10.Scn.Fnt
  2. FoldElems
  3. Syntax10.Scn.Fnt
  4. (*------------------------------------------------------------
  5. Compare files.
  6. Search for a literal string in a sequence of files.
  7. Search for clients and imports of a specific module.
  8. Search for attributes in info elements
  9. Find.Diff ^
  10.     Compares two texts starting from the two most recent
  11.     selections. Sets new selections at the first position where the two
  12.     texts differ.
  13. Find.Domain {filename} ~
  14.     Specify the files in which Find.All should search for a pattern.
  15. Find.All ^
  16.     Searches the selection in the files specified with Find.Domain.
  17.     Lists all lines containing the pattern.
  18. Find.AllInfo ^
  19.     The selection must be of the form
  20.         item = pattern
  21.     where item is one of the headings in an info element
  22.     (Title, Author, ...) and pattern is any character sequence
  23.     up to the end of the selection.
  24.     Lists all modules specified with Find.Domain containing 
  25.     the pattern in their info elements.
  26. Find.Clients (name | ^)
  27.     List all client modules which import module <name>.  Clients are only searched for in the current directory.
  28. Find.Imports (name | ^)
  29.     List all modules imported by module <name>. The modules are listed together with their keys.
  30. ------------------------------------------------------------*)
  31. Syntax10i.Scn.Fnt
  32. InfoElems
  33. Alloc
  34. Syntax10.Scn.Fnt
  35. StampElems
  36. Alloc
  37. 4 May 95
  38. "Title": Find
  39. "Author": HM (mainly), CS (added AllInfo)
  40. "Abstract": Provides you with the possibility to search strings in several
  41.     files, to see which files are imported by several files, to see by which
  42.     files several files are imported and to search several files after additional
  43.     information (title, author, version, keywords etc.).
  44. "Keywords": search, import, client, additional info
  45. "Version": 1.0
  46. "From":  28.10.94 16:40:44
  47. "Until": 
  48. "Changes":
  49. "Hints": This text can again contain arbitrary text elements!
  50. MarkElems
  51. Alloc
  52. Syntax10.Scn.Fnt
  53.     VAR a, b: CHAR;
  54. BEGIN
  55.     Files.Read(r, a); Files.Read(r, b);
  56.     n := SHORT(ASH(ORD(a), 8) + ORD(b))
  57. END ReadInt;
  58. Syntax10.Scn.Fnt
  59.     VAR a, b, c, d: CHAR;
  60. BEGIN
  61.     Files.Read(r, a); Files.Read(r, b); Files.Read(r, c); Files.Read(r, d);
  62.     n := ASH(ORD(a), 24) + ASH(ORD(b), 16) + ASH(ORD(c), 8) + ORD(d)
  63. END ReadLInt;
  64. Syntax10.Scn.Fnt
  65.     VAR t: Texts.Text; beg, end, time: LONGINT;
  66. BEGIN
  67.     Texts.OpenScanner(s, Oberon.Par.text, Oberon.Par.pos); Texts.Scan(s);
  68.     IF (s.class = Texts.Char) & (s.c = "^") THEN
  69.         Oberon.GetSelection(t, beg, end, time);
  70.         IF time >= 0 THEN
  71.             Texts.OpenScanner(s, t, beg); Texts.Scan(s)
  72.         END
  73. END ScanPar;
  74. Syntax10.Scn.Fnt
  75.     VAR v: MenuViewers.Viewer; x, y: INTEGER; t1: Texts.Text; menu: TextFrames.Frame; buf: Texts.Buffer;
  76. BEGIN
  77.     IF Files.Old("Edit.Menu.Text") = NIL THEN menu := TextFrames.NewMenu(name, stdMenu)
  78.     ELSE menu := TextFrames.NewMenu(name, "");
  79.         NEW(t1); Texts.Open(t1, "Edit.Menu.Text");
  80.         NEW(buf); Texts.OpenBuf(buf); Texts.Save(t1, 0, t1.len, buf); Texts.Append(menu.text, buf)
  81.     END;
  82.     Oberon.AllocateUserViewer(0, x, y);
  83.     v := MenuViewers.New(menu, TextFrames.NewText(t, 0), TextFrames.menuH, x, y)
  84. END OpenViewer;
  85. Syntax10.Scn.Fnt
  86.     CONST
  87.         bufSize = 31744; (*2**15 - 1024*)
  88.         textTag = 496; oldTextTag = -4095;
  89.         f: Files.File; r: Files.Rider;
  90.         n, pos: LONGINT;
  91.         i, j, i0: INTEGER;
  92.         ch, patj: CHAR;
  93.         found: BOOLEAN;
  94.         tab: ARRAY 265 OF SHORTINT;
  95.         text: ARRAY bufSize OF CHAR;
  96. BEGIN
  97.     (*----- open file *)
  98.     f := Files.Old(fn);
  99.     IF f = NIL THEN RETURN END;
  100.     Files.Set(r, f, 0); Files.ReadInt(r, i);
  101.     IF (i = textTag) OR (i = oldTextTag) THEN
  102.         pos := 0; (*Files.ReadLInt(r, pos); -- modified to search also in collapsed Fold segments*)
  103.         (*----- initialize tab *)
  104.         Texts.WriteString(w, "--- "); Texts.WriteString(w, fn); Texts.WriteLn(w);
  105.         FOR i := 0 TO 255 DO tab[i] := SHORT(m) END;
  106.         FOR i := 0 TO m-2 DO tab[ORD(pat[i])] := SHORT(m - i - 1) END;
  107.         patj := pat[m-1]; found := FALSE;
  108.         LOOP
  109.             (*----- read text[0..n-1] *)
  110.             n := Files.Length(f) - pos;
  111.             IF n > bufSize THEN n := bufSize END;
  112.             IF n < m THEN EXIT END;
  113.             Files.Set(r, f, pos); Files.ReadBytes(r, text, n);
  114.             (*----- search pat in text[0..n-1] *)
  115.             i := m - 1; j := i;
  116.             WHILE i < n DO
  117.                 IF text[i] = patj THEN i0 := i;
  118.                     REPEAT DEC(i); DEC(j) UNTIL (j < 0) OR (text[i] # pat[j]);
  119.                     IF j < 0 THEN
  120.                         (*------ found: print result *)
  121.                         found := TRUE;
  122.                         WHILE (i >= 0) & (text[i] # CR) & (text[i] >= TAB) DO DEC(i) END;
  123.                         INC(i);
  124.                         Files.Set(r, f, pos + i);
  125.                         REPEAT Files.Read(r, ch); Texts.Write(w, ch); INC(i) UNTIL (ch = CR) OR (ch < TAB) OR (r.eof)
  126.                     ELSE i := i + tab[ORD(text[i])]
  127.                     END;
  128.                     IF i <= i0 THEN i := i0 + 1 END;
  129.                     j := m - 1
  130.                 ELSE i := i + tab[ORD(text[i])]
  131.                 END
  132.             END;
  133.             pos := pos + i - m + 1
  134.         END;
  135.         IF found THEN Texts.WriteLn(w); Texts.Append(out, w.buf) ELSE Texts.OpenWriter(w) END
  136.     ELSE
  137.         Texts.WriteString(w, fn); Texts.WriteString(w, " is no text file"); Texts.WriteLn(w);
  138.         Texts.Append(Oberon.Log, w.buf)
  139. END Search;
  140. Syntax10.Scn.Fnt
  141.     VAR f: Files.File; r: Files.Rider; ch: CHAR; s: ARRAY 32 OF CHAR; i, j, dummy, entries, cmds, ptrs, imps: INTEGER; key: LONGINT;
  142. BEGIN
  143.     f := Files.Old(name);
  144.     IF f # NIL THEN
  145.         i := 0; WHILE name[i] # 0X DO INC(i) END;
  146.         name[i-3] := "M"; name[i-2] := "o"; name[i-1] := "d";
  147.         Files.Set(r, f, 6);
  148.         ReadInt(r, entries); ReadInt(r, cmds); ReadInt(r, ptrs); ReadInt(r, dummy); ReadInt(r, imps);
  149.         Files.Set(r, f, 34); REPEAT Files.Read(r, ch) UNTIL ch = 0X; (*skip name*)
  150.         Files.Set(r, f, Files.Pos(r) + 1 + 2*entries + 1); (*skip entries*)
  151.         FOR i := 1 TO cmds DO  (*skip commands*)
  152.             REPEAT Files.Read(r, ch) UNTIL ch = 0X;
  153.             ReadInt(r, dummy)
  154.         END;
  155.         Files.Set(r, f, Files.Pos(r) + 1 + 4*ptrs + 1); (*skip pointer offsets*)
  156.         FOR i := 1 TO imps DO
  157.             ReadLInt(r, key);
  158.             j := 0; REPEAT Files.Read(r, ch); s[j] := ch; INC(j) UNTIL ch = 0X;
  159.             IF s = fileName THEN Out.String("   "); Out.String(name); Out.Ln END
  160.         END
  161. END CheckObjFile;
  162. Syntax10.Scn.Fnt
  163. Syntax8i.Scn.Fnt
  164.     BEGIN
  165.         WHILE (npos >= 0) & (mpos >= 0) & (mask[mpos] # "*") DO
  166.             IF name[npos] # mask[mpos] THEN RETURN FALSE END;
  167.             DEC(npos); DEC(mpos)
  168.         END;
  169.         (* ----- name empty | mask empty | mask ends with "*" *)
  170.         IF mpos < 0 THEN RETURN npos < 0 END;
  171.         (* ----- name empty | mask ends with "*" *)
  172.         WHILE (mpos >= 0) & (mask[mpos] = "*") DO DEC(mpos) END;
  173.         IF mpos < 0 THEN RETURN TRUE END;
  174.         (* ----- name empty | mask still to be matched *)
  175.         WHILE npos >= 0 DO
  176.             IF Match(name, mask, npos, mpos) THEN RETURN TRUE END;
  177.             DEC(npos)
  178.         END;
  179.         RETURN FALSE
  180.     END Match;
  181. Syntax10b.Scn.Fnt
  182. Syntax10.Scn.Fnt
  183.     VAR s: Texts.Scanner; f, last: File;
  184. BEGIN file := NIL; last := NIL;
  185.     ScanPar(s);
  186.     WHILE (s.class = Texts.Name) OR (s.class = Texts.String) DO
  187.         NEW(f); f.next := NIL;
  188.         IF last = NIL THEN file := f ELSE last.next := f END;
  189.         last := f;
  190.         COPY(s.s, f.name);
  191.         Texts.Scan(s);
  192.         WHILE (s.class = Texts.Char) & (s.c = "/") DO Texts.Scan(s); Texts.Scan(s) END
  193. END Domain;
  194. Syntax10.Scn.Fnt
  195. FoldElems
  196. Syntax10.Scn.Fnt
  197.         VAR t: Texts.Text; r: Texts.Reader; beg, end, time: LONGINT; ch: CHAR;
  198.     BEGIN
  199.         Oberon.GetSelection(t, beg, end, time);
  200.         IF time > 0 THEN
  201.             Texts.OpenReader(r, t, beg); m := 0;
  202.             WHILE beg < end DO Texts.Read(r, ch);
  203.                 IF m < 127 THEN pat[m] := ch END;
  204.                 INC(m); INC(beg)
  205.             END;
  206.             pat[m] := 0X
  207.         END;
  208.     END ReadPattern;
  209.     VAR pat: ARRAY 128 OF CHAR; m: INTEGER; f: File;
  210.     PROCEDURE ReadPattern (VAR pat: ARRAY OF CHAR; VAR m: INTEGER);    
  211. BEGIN
  212.     ReadPattern(pat, m);
  213.     out := TextFrames.Text("");
  214.     OpenViewer(pat, out); f := file;
  215.     WHILE f # NIL DO
  216.         Search(f.name, pat, m);
  217.         f := f.next
  218. END All;
  219. Syntax10.Scn.Fnt
  220. FoldElems
  221. Syntax10.Scn.Fnt
  222.         VAR time: LONGINT; v: Viewers.Viewer; x: INTEGER; f: Display.Frame;
  223.     BEGIN
  224.         time := -1; x := 0; F := NIL;
  225.         WHILE x < Display.Width DO
  226.             v := Viewers.This(x, 0);
  227.             WHILE v.state > 1 DO
  228.                 f := v.dsc.next;
  229.                 WITH f: TextFrames.Frame DO
  230.                     IF f.hasSel & (f.time > time) THEN F := f; pos := f.selbeg.pos; time := f.time END
  231.                 ELSE
  232.                 END;
  233.                 v := Viewers.Next(v)
  234.             END;
  235.             x := x + v.W
  236.         END;
  237.         IF F # NIL THEN TextFrames.RemoveSelection(F); TextFrames.RemoveCaret(F) END
  238.     END GetSelection;
  239. Syntax10.Scn.Fnt
  240.         VAR x: LONGINT;
  241.     BEGIN
  242.         IF pos > TextFrames.Pos(f, f.X + f.W - 1, f.Y) THEN 
  243.             x := pos - 150; IF x < 0 THEN x := 0 END;
  244.             TextFrames.Show(f, x)
  245.         END;
  246.         TextFrames.SetSelection(f, pos, pos+1)
  247.     END ShowSelection;
  248.     VAR f1, f2: TextFrames.Frame; p1, p2: LONGINT; r1, r2: Texts.Reader; ch1, ch2: CHAR;
  249.     PROCEDURE GetSelection(VAR F: TextFrames.Frame; VAR pos: LONGINT);    
  250.     PROCEDURE ShowSelection(f: TextFrames.Frame; pos: LONGINT);    
  251. BEGIN
  252.     GetSelection(f1, p1); GetSelection(f2, p2);
  253.     IF (f1 # NIL) & (f2 # NIL) THEN
  254.         Texts.OpenReader(r1, f1.text, p1); 
  255.         Texts.OpenReader(r2, f2.text, p2); 
  256.         REPEAT
  257.             Texts.Read(r1, ch1); INC(p1); Texts.Read(r2, ch2); INC(p2);
  258.         UNTIL (ch1 # ch2) OR (ch1 = 0X);
  259.         IF (ch1 = 0X) OR (ch2 = 0X) THEN DEC(p1); DEC(p2) END;
  260.         ShowSelection(f1, p1-1); ShowSelection(f2, p2-1)
  261. END Diff;
  262. Syntax10.Scn.Fnt
  263. FoldElems
  264. Syntax10.Scn.Fnt
  265.             Texts.OpenScanner(menuS, menuT, 0); Texts.Scan(menuS);
  266.             WHILE ~menuS.eot DO
  267.                 IF (menuS.class = Texts.String) & (menuS.s = item) THEN (* if it is the right item *)
  268.                     Texts.OpenReader(copyR, t, Texts.Pos(menuS) - 2); Texts.Read(copyR, copyCh); i := 0; r2 := r;
  269.                     WHILE (~copyR.eot) & (copyCh # '"') DO INC(i); Texts.Read(copyR, copyCh) END;
  270.                     NEW(text, i + 1); r := r2; i := 0;
  271.                     WHILE (~copyR.eot) & (copyCh # '"') DO
  272.                         INC(i); text[i] := copyCh; Out.Char(copyCh);
  273.                         Texts.Read(copyR, copyCh)
  274.                     END;
  275.                     text[i] := 0X;
  276.                     IF Match(text^, pat, i - 1, m - 1) THEN FOR i := 0 TO i DO Texts.Write(w, ch) END END;
  277.                     Texts.OpenScanner(menuS, t, Texts.Pos(copyR) - 1); 
  278.                 END;
  279.                 Texts.Scan(menuS);
  280.             END
  281.         END; (* character was no InfoElem *)
  282.         Texts.Read(r, ch)
  283.     END;
  284.         t, infoT: Texts.Text; r, infoR: Texts.Reader;
  285.         ch, commentCh: CHAR; menuItem: ARRAY 16 OF CHAR;
  286.         text: ARRAY 10000 OF CHAR;
  287.         i, textLen, patLen: LONGINT;
  288. BEGIN
  289.     Texts.WriteString(w, "--- "); Texts.WriteString(w, fn); Texts.WriteString(w, ", matches for "); Texts.WriteString(w, item);
  290.     Texts.WriteString(w, " = "); Texts.WriteString(w, pat); Texts.WriteLn(w);
  291.     NEW(t); Texts.Open(t, fn);
  292.     Texts.OpenReader(r, t, 0); Texts.ReadElem(r);
  293.     WHILE ~r.eot DO
  294.         IF r.elem IS InfoElems.Elem THEN    (* InfoElem found *)
  295.             infoT := r.elem(InfoElems.Elem).menu;    (* get text of InfoElem *)
  296.             Texts.OpenReader(infoR, infoT, 0); Texts.Read(infoR, ch);
  297.             WHILE ~infoR.eot DO
  298.                 WHILE (~infoR.eot) & (ch # '"') & (ch # "'") DO Texts.Read(infoR, ch) END;
  299.                 IF ~infoR.eot THEN commentCh := ch END; 
  300.                 Texts.Read(infoR, ch); i := 0;
  301.                 WHILE (~infoR.eot) & (ch # commentCh) DO 
  302.                     menuItem[i] := ch;
  303.                     Texts.Read(infoR, ch); INC(i)
  304.                 END;
  305.                 menuItem[i] := 0X;
  306.                 WHILE (~infoR.eot) & ((ch = "'") OR (ch = '"') OR (ch = " ") OR (ch = TAB) OR (ch = ":")) DO
  307.                     Texts.Read(infoR, ch)
  308.                 END;
  309.                 i := 0;
  310.                 WHILE (~infoR.eot) & (ch # '"') & (ch # "'") & (i < LEN(text) - 1) DO
  311.                     IF (ch # TAB) & (ch # CR) THEN text[i] := ch; INC(i) END;
  312.                     Texts.Read(infoR, ch)
  313.                 END;
  314.                 text[i] := 0X;
  315.                 IF menuItem = item THEN
  316.                     patLen := 0; WHILE pat[patLen] # 0X DO INC(patLen) END;
  317.                     textLen := 0; WHILE text[textLen] # 0X DO INC(textLen) END;
  318.                     IF Match(text, pat, textLen, patLen) THEN i := 0;
  319.                         WHILE text[i] # 0X DO Texts.Write(w, text[i]); INC(i) END
  320.                     END
  321.                 END
  322.             END
  323.         END;
  324.         Texts.ReadElem(r)
  325.     END;
  326.     Texts.WriteLn(w); Texts.Append(out, w.buf);
  327. END InfoSearch;
  328. Syntax10.Scn.Fnt
  329. Syntax10i.Scn.Fnt
  330. FoldElems
  331. Syntax10.Scn.Fnt
  332.         VAR t: Texts.Text; r: Texts.Reader; s: Texts.Scanner; beg, end, time: LONGINT; ch: CHAR;
  333.     BEGIN
  334.         Oberon.GetSelection(t, beg, end, time);
  335.         IF time > 0 THEN
  336.             Texts.OpenScanner(s, t, beg); Texts.Scan(s);
  337.             IF s.class IN {Texts.Name, Texts.String} THEN
  338.                 COPY(s.s, item);
  339.                 Texts.Scan(s);
  340.                 IF (s.class = Texts.Char) & (s.c = "=") THEN
  341.                     Texts.Scan(s);
  342.                     Texts.OpenReader(r, t, Texts.Pos(s) - 2); m := 0; beg := Texts.Pos(s) - 2;
  343.                     WHILE beg < end DO 
  344.                         Texts.Read(r, ch);
  345.                         IF m < (LEN(pat) - 1) THEN pat[m] := ch END;
  346.                         INC(m); INC(beg)
  347.                     END;
  348.                     pat[m] := 0X
  349.                 END;
  350.             END;
  351.         END;
  352.     END ReadPattern;
  353.     VAR pat: ARRAY 128 OF CHAR; item: ARRAY 16 OF CHAR; m: INTEGER; f: File;
  354.     PROCEDURE ReadPattern;    
  355. BEGIN
  356.     ReadPattern;
  357.     out := TextFrames.Text("");
  358.     OpenViewer(pat, out); f := file;
  359.     WHILE f # NIL DO
  360.         InfoSearch(f.name, pat, item);
  361.         f := f.next
  362. END AllInfo;
  363. Syntax10.Scn.Fnt
  364.     VAR i: INTEGER;
  365. BEGIN
  366.     In.Open; In.Name(fileName);
  367.     IF In.Done THEN
  368.         i := 0; WHILE fileName[i] # 0X DO INC(i) END;
  369.         IF (i >= 4) & (fileName[i-4] = ".") THEN fileName[i-4] := 0X END;
  370.         Out.String("modules importing "); Out.String(fileName); Out.Char(":"); Out.Ln;
  371.         Directories.EnumerateFiles(0, 0, "*.Obj", CheckObjFile)
  372.     END;
  373. END Clients;
  374. Syntax10.Scn.Fnt
  375.     CONST TAB = 9X;
  376.     VAR f: Files.File; r: Files.Rider; ch: CHAR; a: ARRAY 256 OF CHAR; i, j, dummy, entries, cmds, ptrs, imps: INTEGER; key: LONGINT;
  377. BEGIN
  378.     In.Open; In.Name(a);
  379.     IF In.Done THEN
  380.         i := 0; WHILE a[i] # 0X DO INC(i) END;
  381.         IF (i >= 4) & (a[i-4] = ".") THEN i := i - 4 ELSE a[i] := "." END;
  382.         a[i+1] := "O"; a[i+2] := "b"; a[i+3] := "j"; a[i+4] := 0X;
  383.         f := Files.Old(a);
  384.         IF f # NIL THEN
  385.             Files.Set(r, f, 6);
  386.             ReadInt(r, entries); ReadInt(r, cmds); ReadInt(r, ptrs); ReadInt(r, dummy); ReadInt(r, imps);
  387.             Files.Set(r, f, 34); REPEAT Files.Read(r, ch) UNTIL ch = 0X; (*skip name*)
  388.             Files.Set(r, f, Files.Pos(r) + 1 + 2*entries + 1); (*skip entries*)
  389.             FOR i := 1 TO cmds DO  (*skip commands*)
  390.                 REPEAT Files.Read(r, ch) UNTIL ch = 0X;
  391.                 ReadInt(r, dummy)
  392.             END;
  393.             Files.Set(r, f, Files.Pos(r) + 1 + 4*ptrs + 1); (*skip pointer offsets*)
  394.             Out.String(a); Out.Char(TAB); Out.Char("["); Out.Int(key, 0); Out.String("] imports:"); Out.Ln;
  395.             FOR i := 1 TO imps DO
  396.                 ReadLInt(r, key);
  397.                 j := 0; REPEAT Files.Read(r, ch); a[j] := ch; INC(j) UNTIL ch = 0X;
  398.                 Out.Char(TAB); Out.String(a); Out.Char(TAB); Out.Char("["); Out.Int(key, 0); Out.Char("]"); Out.Ln
  399.             END
  400.         END
  401. END Imports;
  402. Documentation
  403. MODULE Find;    
  404. IMPORT Display, Files, Directories, Oberon, Viewers, MenuViewers, TextFrames, Texts, In, Out, InfoElems;
  405. CONST
  406.     stdMenu = "System.Close  System.Copy  System.Grow  Edit.Search  Edit.Store ";
  407.     CR = 0DX; TAB = 09X;
  408.     File = POINTER TO FileDesc;
  409.     FileDesc = RECORD
  410.         name: ARRAY 256 OF CHAR;
  411.         next: File
  412.     END;
  413.     file: File;
  414.     fileName: ARRAY 256 OF CHAR;
  415.     w: Texts.Writer;
  416.     out: Texts.Text;
  417. PROCEDURE 
  418. ReadInt (VAR r: Files.Rider; VAR n: INTEGER);    
  419. PROCEDURE 
  420. ReadLInt (VAR r: Files.Rider; VAR n: LONGINT);    
  421. PROCEDURE 
  422. ScanPar (VAR s: Texts.Scanner);    
  423. PROCEDURE 
  424. OpenViewer(name: ARRAY OF CHAR; t: Texts.Text);    
  425. PROCEDURE 
  426. Search (fn: ARRAY OF CHAR; pat: ARRAY OF CHAR; m: INTEGER);    
  427. PROCEDURE 
  428. CheckObjFile (VAR name: ARRAY OF CHAR; time, date, len: LONGINT; isDir: BOOLEAN; VAR continue: BOOLEAN);    
  429. PROCEDURE 
  430. Match (VAR name, mask: ARRAY OF CHAR; npos, mpos: LONGINT): BOOLEAN;
  431. (* -- commands -- *)
  432. PROCEDURE 
  433. Domain*;    (* {filename} ~ *)    
  434. PROCEDURE 
  435. All*;    (* ^ *)    
  436. PROCEDURE 
  437. Diff*;    (* compares two texts from the last two selections; sets selection to first difference *)    
  438. (* -- PowerMac-specific commands -- *)
  439. PROCEDURE 
  440. InfoSearch (fn: ARRAY OF CHAR; pat: ARRAY OF CHAR; item: ARRAY OF CHAR);
  441. PROCEDURE 
  442. AllInfo*; (** ^         format: item = searchPattern where item IN {"Title", "Author", "Abstract", 
  443.                                                 "Keywords", "Version", "From", "Until", "Hints", "Changes"}, searchPattern 
  444.                                                 must match exactly or contain asterisks *)    
  445. PROCEDURE 
  446. Clients*;    
  447. PROCEDURE 
  448. Imports*;    
  449. BEGIN
  450.     file := NIL; Texts.OpenWriter(w)
  451. END Find.
  452.